#include "C_gl_Texture_2D.h"

#include "../glCommon/glTexture.h"

#include <cuda_runtime.h>
#include <cuda_gl_interop.h>

class C_gl_Device;

C_gl_Texture_2D::C_gl_Texture_2D(const S_api_Texture2D_Desc *pDesc, const S_api_Subresource_Data *pInitialData, const I_api_Device * pDevice) 
	: I_api_Texture_2D(pDesc, pInitialData, pDevice)
{
	GL_TEXTURE_DESC glTexDesc(pDesc->Width, pDesc->Height, GL_TARGET_TEXTURE_2D);
	GL_SUBRESOURCE_DATA glSubresourceData;

	glSubresourceData.Type = pDevice->FormatToOpenGLType(pInitialData->Format);
	glSubresourceData.Format = pDevice->FormatToOpenGLFormat(pInitialData->Format);
	glTexDesc.Format = pDevice->FormatToOpenGLInternal(pDesc->Format);

	glSubresourceData.pSysMem = pInitialData->pSysMem;
	glSubresourceData.SysMemPitch = pInitialData->SysMemPitch;
	glSubresourceData.SysMemSlicePitch = pInitialData->SysMemSlicePitch;

	glTexDesc.MipLevels = pDesc->MipLevels;
	glTexDesc.ArraySize = pDesc->ArraySize;

	m_Id = glCreateTexture(&glTexDesc, &glSubresourceData, NULL);

	m_pResource = NULL;

	if (pDesc->BindFlags & E_api_Bind_Shader_Resource)
	{
		//cudaError_t error = cudaGetLastError();
		//cudaGraphicsGLRegisterImage(&m_pResource, m_Id, glTexDesc.Target, cudaGraphicsMapFlagsReadOnly);
		//error = cudaGetLastError();
		//if (error != cudaSuccess)
		//{
		//	fprintf(stderr, "cuda error in %d file %s \n", __LINE__, __FILE__);
		//	fprintf(stderr, "%s \n", cudaGetErrorString(error));
		//}
	}

	m_Flag = 0;
}

C_gl_Texture_2D::~C_gl_Texture_2D()
{
	glDeleteTextures(1, &m_Id);

	if (m_pResource)
	{
		cudaGraphicsUnregisterResource(m_pResource);
	}
}

bool C_gl_Texture_2D::Map(u32 Subresource, E_api_Map MapType, u32 MapFlags, S_api_Mapped_Texture2D *pMappedTex2D)
{ 
	if (MapType == E_api_Map_Lock)
	{
		s_mapped_resource res;

		res.pResource = m_pResource;
		res.Subresource = Subresource;
		res.Flag = MapType;

		cudaArray * pArray = NULL;

		u32 arrayIdx = Subresource / m_Desc.MipLevels;
		u32 mipSlice = Subresource - arrayIdx * m_Desc.MipLevels;		

		m_Flag = E_api_Map_Lock;

		cudaGraphicsMapResources(1, &res.pResource, 0);

		cudaGraphicsSubResourceGetMappedArray(&pArray, res.pResource, arrayIdx, mipSlice);

		pMappedTex2D->pData = pArray;
	}
	return true; 
}

bool C_gl_Texture_2D::Unmap(u32 Subresource)
{ 
	for (u32 iResource = 0; iResource < m_pResourceList.size(); iResource++)
	{
		if (m_pResourceList[iResource]->Subresource == Subresource) {
			if (m_pResourceList[iResource]->Flag == E_api_Map_Lock)
			{		
				cudaGraphicsUnmapResources(1, &m_pResourceList[iResource]->pResource, 0);

				m_pResourceList[iResource]->Flag = 0;
			}
		}
	}
	return true; 
}